#include "myiic.h"

void iic_delay_us(uint16_t dly_cnt)
{
	while(dly_cnt--)
  {
    __nop();
    __nop();
  }
}
void iic_delay_ms(uint16_t dly_cnt)
{
	while(dly_cnt--)
  {
    iic_delay_us(1000);
  }
} 
 
//初始化IIC
void IIC_Init(void)
{					     
	gpio_config_out(SCLK);
	gpio_config_out(SDAT);

	SCL0_HIGH();
	SDA0_HIGH();
	delay_ms(10);
}
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	SDA0_HIGH();	  	  
	SCL0_HIGH();
	delay_us(4);
 	SDA0_LOW();//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	SCL0_LOW();//钳住I2C总线，准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	SCL0_LOW();
	SDA0_LOW();//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	SCL0_HIGH(); 
	SDA0_HIGH();//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
uint8_t IIC_Wait_Ack(void)
{
	uint8_t ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	SDA0_HIGH();delay_us(1);	   
	SCL0_HIGH();delay_us(1);	 
	while(SDA0_READ())
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL0_LOW();//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	SCL0_LOW();
	SDA_OUT();
	SDA0_LOW();
	delay_us(2);
	SCL0_HIGH();
	delay_us(2);
	SCL0_LOW();
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	SCL0_LOW();
	SDA_OUT();
	SDA0_HIGH();
	delay_us(2);
	SCL0_HIGH();
	delay_us(2);
	SCL0_LOW();
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答			  
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
	SDA_OUT(); 	    
    SCL0_LOW();//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
//        gpio_set(SDAT,(txd&0x80)>>7);
		if((txd&0x80)>>7)
			SDA0_HIGH();
		else
			SDA0_LOW();
		txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		SCL0_HIGH();
		delay_us(2); 
		SCL0_LOW();	
		delay_us(2);
    }	 
} 	    
//读1个字节，ack=1时，发送ACK，ack=0，发送nACK   
uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        SCL0_LOW(); 
        delay_us(2);
		SCL0_HIGH();
        receive<<=1;
        if (SDA0_READ())receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

static uint8_t Soft_I2C_SendByte(uint8_t soft_i2c_data)//发送一字节，带返回
{
 	uint8_t i;
    SDA_OUT(); 	 
	SCL0_LOW();
 	for(i=0; i<8; i++)
 	{
  		if(soft_i2c_data & 0x80)
            SDA0_HIGH();
   		else
            SDA0_LOW();
  		soft_i2c_data <<= 1;
  		delay_us(10);

  		SCL0_HIGH();
  		delay_us(10);
  		SCL0_LOW();
  		delay_us(10);
 	}
	//return Soft_I2C_Wait_Ack();
  return IIC_Wait_Ack();
}

static uint8_t Soft_I2C_ReceiveByte(void)//接收一字节，带返回
{
	uint8_t i,soft_i2c_data;

 	SDA0_HIGH();
 	SCL0_LOW();
 	soft_i2c_data = 0;
    SDA_IN();      //SDA设置为输入 
 	for(i=0; i<8; i++)
 	{
  		SCL0_HIGH();
  		delay_us(10);
  		soft_i2c_data <<= 1;

  		if(SDA0_READ())
  			soft_i2c_data |= 0x01;

  		SCL0_LOW();
  		delay_us(10);
 	}
//	Soft_I2C_SendNACK();
    IIC_NAck();
 	return soft_i2c_data;
}

static uint8_t Soft_I2C_ReceiveByte_WithACK(void)//接收应答
{
	uint8_t i,soft_i2c_data;

 	SDA0_HIGH();
 	SCL0_LOW();
 	soft_i2c_data = 0;
    SDA_IN();      //SDA设置为输入 
 	for(i=0; i<8; i++)
 	{
  		SCL0_HIGH();
  		delay_us(10);
  		soft_i2c_data <<= 1;

  		if(SDA0_READ())
  			soft_i2c_data |= 0x01;

  		SCL0_LOW();
  		delay_us(10);
 	}
//	Soft_I2C_SendACK();
  IIC_Ack();
 	return soft_i2c_data;
}

static uint8_t Soft_DMP_I2C_Write(uint8_t soft_dev_addr, uint8_t soft_reg_addr, uint8_t soft_i2c_len,unsigned char *soft_i2c_data_buf)
{
    uint8_t i, result = 0;
	//Soft_I2C_START();
    IIC_Start();
	result = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Transmitter);
	if(result != 0) return result;

	result = Soft_I2C_SendByte(soft_reg_addr);
	if(result != 0) return result;

	for (i=0; i<soft_i2c_len; i++)
	{
		result = Soft_I2C_SendByte(soft_i2c_data_buf[i]);
		if (result != 0) return result;
	}
//	Soft_I2C_STOP();
    IIC_Stop();
	return 0x00;
}

static uint8_t Soft_DMP_I2C_Read(uint8_t soft_dev_addr, uint8_t soft_reg_addr, uint8_t soft_i2c_len,unsigned char *soft_i2c_data_buf)
{
	uint8_t result;

//	Soft_I2C_START();
  IIC_Start();
	result  = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Transmitter);
	if(result != 0) return result;

	result = Soft_I2C_SendByte(soft_reg_addr);
   //printf("addr:0x%x\n",result);
	if(result != 0) return result;

//	Soft_I2C_START();
  IIC_Start();
	result = Soft_I2C_SendByte(soft_dev_addr << 1 | I2C_Direction_Receiver);
	if(result != 0) return result;

    while (soft_i2c_len)
	{
		if (soft_i2c_len == 1)
			*soft_i2c_data_buf = Soft_I2C_ReceiveByte();
        else
        	*soft_i2c_data_buf = Soft_I2C_ReceiveByte_WithACK();
        soft_i2c_data_buf ++;
        soft_i2c_len --;
    }
//	Soft_I2C_STOP();
    IIC_Stop();
    return 0x00;
}

/**
  * @brief  向IIC设备的寄存器连续写入数据，带超时重试设置，供mpu接口调用
  * @param  Address: IIC设备地址
  * @param  RegisterAddr: 寄存器地址
  * @param  RegisterLen: 要写入数据的长度
  * @param  RegisterValue: 要指向写入数据的指针
  * @retval 0正常，非0异常
  */
int Sensors_I2C_WriteRegister(unsigned char slave_addr,
                              unsigned char reg_addr,
                              unsigned short len,
                              const unsigned char *data_ptr)
{
    char retries = 0;
    int ret = 0;
    unsigned short retry_in_mlsec = 5;

	tryWriteAgain:
    ret = 0;
    ret = Soft_DMP_I2C_Write( slave_addr, reg_addr, len, (unsigned char *)data_ptr);

    if(ret && retry_in_mlsec)
    {
        if( retries++ > 4 )
            return ret;

        delay_ms(retry_in_mlsec);
        goto tryWriteAgain;
    }
    return ret;
}

/**
  * @brief  向IIC设备的寄存器连续读出数据,带超时重试设置，供mpu接口调用
  * @param  Address: IIC设备地址
  * @param  RegisterAddr: 寄存器地址
  * @param  RegisterLen: 要读取的数据长度
  * @param  RegisterValue: 指向存储读出数据的指针
  * @retval 0正常，非0异常
  */
int Sensors_I2C_ReadRegister(unsigned char slave_addr,
                             unsigned char reg_addr,
                             unsigned short len,
                             unsigned char *data_ptr)
{
    char retries = 0;
    int ret = 0;
    unsigned short retry_in_mlsec = 5;

	tryReadAgain:
    ret = 0;
    ret = Soft_DMP_I2C_Read( slave_addr, reg_addr, len, (unsigned char *)data_ptr);

    if(ret && retry_in_mlsec)
    {
        if( retries++ > 4 )
            return ret;

        delay_ms(retry_in_mlsec);
        goto tryReadAgain;
    }
    return ret;
}

